picasaGadget = function(moduleId, mapContainerId, slideshowContainerId) {
    google.load("feeds", "1");

    this.moduleId_ = moduleId;
    this.mapContainerId_ = mapContainerId;
    this.slideshowContainerId_ = slideshowContainerId;

    this.data_ = [];
    this.currentItem_ = 0;
    this.dataCount_ = 0;
    this.status_ = null;

    this.maxItems_ = 100;
    this.gPhotoNameSpace_ = {name:'gphoto', uri:'http://schemas.google.com/photos/2007'};
    this.gMLNameSpace_ = {name:'gml', uri:'http://www.opengis.net/gml'};
    this.mediaNameSpace = {name:'media', uri:'http://search.yahoo.com/mrss/'};
    this.username_ = this.prefs_.getString('username');
    this.autoshow_ = this.prefs_.getBool('autoshow');
    this.useTabs_ = this.prefs_.getBool('slideshow');
    _IG_SetTitle(this.username_ + '\'s Photo Map')
    this.url_ = 'http://picasaweb.google.com/data/feed/api/user/' + this.username_ + '?access=public&kind=album&thumsize=48&imgmax=48';

    if (this.useTabs_) {
        this.tabs_ = new _IG_Tabs(this.moduleId_, "Two");
        this.tabs_.alignTabs('left');
        this.tabs_.addTab('Photo map', 'map');
        this.tabs_.setSelectedTab(0);
    }
    this.IS_IE = navigator.appName == "Microsoft Internet Explorer";

    this.FIRST = 'FIRST';
    this.LAST = 'LAST';

    google.setOnLoadCallback(bind(this.render, this));
};

picasaGadget.getCacheBuster = function() {
  return picasaGadget.BUST_CACHE ? ('nocache=' + new Date().getTime()) : '';
};

// Inherit from MapGadget class.
picasaGadget.prototype = new MapGadget();
picasaGadget.prototype.constructor = picasaGadget;
picasaGadget.prototype.parent = MapGadget.prototype;

picasaGadget.prototype.render = function() {
    this.parent.render.call(this);
    _IG_FetchXmlContent(
            this.url_,
            bind(this.handleResponse, this));
};

picasaGadget.prototype.handleResponse = function(feed){
    if (!typeof(feed.getElementsByTagName) == 'function') {
        _gel('map').innerHTML = feed;
    } else {
        var entries = feed.getElementsByTagName('entry');
        if (entries.length == 0) {
            _gel('map').innerHTML = 'User "' + this.username_ + '" has no public albums which have been geotagged.';  
        } else {
            for (var i=0, entry; (entry = entries[i]) && (i < this.maxItems_); i++) {
                var titleNode = entry.getElementsByTagName('title');
                var title = (titleNode[0] && titleNode[0].firstChild) ? titleNode[0].firstChild.nodeValue : 'Untitled';

                var nameNode = _getn(entry, this.gPhotoNameSpace_, 'name');
                var name = (nameNode[0] && nameNode[0].firstChild) ? nameNode[0].firstChild.nodeValue : '';

                var latLongNode = _getn(entry, this.gMLNameSpace_, 'pos');
                var latLong = (latLongNode[0] && latLongNode[0].firstChild) ? latLongNode[0].firstChild.nodeValue.split(' ') : null;

                var thumbUrlNode = _getn(entry, this.mediaNameSpace, 'content');
                var thumbUrl = thumbUrlNode[0] ? thumbUrlNode[0].getAttribute('url') : '';

                var locationNode = _getn(entry, this.gPhotoNameSpace_, 'location');
                var location = (locationNode[0] && locationNode[0].firstChild) ? locationNode[0].firstChild.nodeValue : '';

                var timeStampNode = _getn(entry, this.gPhotoNameSpace_, 'timestamp');
                var date = new Date();
                if (timeStampNode[0] && timeStampNode[0].firstChild) {
                    date.setTime(timeStampNode[0].firstChild.nodeValue);
                }

                var numPhotosNode = _getn(entry, this.gPhotoNameSpace_, 'numphotos');
                var numPhotos = (numPhotosNode[0] && numPhotosNode[0].firstChild) ? numPhotosNode[0].firstChild.nodeValue : '';

                if (latLong) {
                    var point = new GLatLng(latLong[0], latLong[1]);
                    var marker = this.createMarker(point, title, thumbUrl, name, location, date, numPhotos, this.dataCount_++);
                    this.map_.addOverlay(marker);
                }
            }

            if (entries.length > 1) {
                var first = _dce('span');
                first.innerHTML = '<a href="javascript:void(0)">&laquo;</a> ';
                first.onclick = bind(this.navigate, this, this.FIRST);

                var prev = _dce('span');
                prev.innerHTML = '<a href="javascript:void(0)">&lsaquo; older</a> ';
                prev.onclick = bind(this.navigate, this, 1);

                var status = _dce('span');
                status.id = 'status';

                var next = _dce('span');
                next.innerHTML = ' <a href="javascript:void(0);">newer &rsaquo;</a>'
                next.onclick = bind(this.navigate, this, -1);

                var last = _dce('span');
                last.innerHTML = '<a href="javascript:void(0)">&raquo;</a> ';
                last.onclick = bind(this.navigate, this, this.LAST);

                this.controls = _dce('div');
                this.controls.style.visibility = 'hidden';
                this.controls.className = 'controls'
                this.controls.appendChild(first);
                this.controls.appendChild(prev);
                this.controls.appendChild(status);
                this.controls.appendChild(next);
                this.controls.appendChild(last);

                _gel(this.mapContainerId_).parentNode.appendChild(this.controls);

                if (this.autoshow_) {
                    this.navigate(0);
                }
            }
        }
        _IG_AdjustIFrameHeight();
    }
};

picasaGadget.prototype.navigate = function(direction) {

    if (direction == this.FIRST) {
        this.currentItem_ = this.data_.length - 1;
    } else if (direction == this.LAST) {
        this.currentItem_ = 0;
    } else {
        do {
            this.currentItem_ += direction;
            this.currentItem_ = Math.min(this.data_.length - 1, this.currentItem_);
            this.currentItem_ = Math.max(0, this.currentItem_);
        }
        while ((this.data_[(this.currentItem_)] == null) &&
               (this.currentItem_ > 0) &&
               (this.currentItem_ < this.data_.length)) {
    }
}

    this.setStatus(this.currentItem_);
    var current = this.data_[this.currentItem_];
    current.marker.openInfoWindow(current.infoWindow);
    this.controls.style.visibility = 'visible';
};

picasaGadget.prototype.setStatus = function(current) {
    this.status_ = this.status_ || _gel('status');
    this.status_.innerHTML = '<b>' + (this.dataCount_ - current) + '</b> of <b>' + this.dataCount_ + '</b>'
};

picasaGadget.prototype.createMarker = function(point, title, thumbUrl, name, location, date, numPhotos, i) {
    var marker = new GMarker(point);
    var infoWindow = this.createInfoWindow(title, thumbUrl, name, location, date, numPhotos);
    GEvent.addListener(marker, 'click', bind(function() {
        marker.openInfoWindow(infoWindow);
        this.controls.style.visibility = 'visible';
        this.currentItem_ = i;
        this.setStatus(i);
    }, this));
    GEvent.addListener(this.map_, 'infowindowclose', bind(function() {
        this.controls.style.visibility = 'hidden';
      }, this)); 

    this.data_[i] = {marker: marker, infoWindow: infoWindow};

    return marker;
};

picasaGadget.prototype.createInfoWindow = function(title, thumbUrl, name, location, date, numPhotos) {
    var infoWindow = _dce('div');
    infoWindow.className = 'infoWindow';

    var albumUrl = 'http://picasaweb.google.com/' + this.username_ + '/' + name;

    var p = _dce('p');
    var b = _dce('b');
    var titleNode = document.createTextNode(title)
    b.appendChild(titleNode);
    p.appendChild(b);

    var table = _dce('table');
    table.style.cellPadding = 0;
    table.style.cellSpacing = 0;
    table.className = 'table';

    var tbody = _dce('tbody');
    var tr = _dce('tr');

    var left = _dce('td');
    left.innerHTML = '<a target="_blank" href="' + albumUrl + '"><img width="48" height="48" src="' + thumbUrl + '"/></a>';

    var a = _dce('a');

    // Google Feed API Slideshow seems to not work in IE at the moment.
    if (this.IS_IE || !this.useTabs_) {
        a.innerHTML = 'View album &raquo;'
        a.href = albumUrl;
        a.target = '_blank';

        // Hide tabs.
        var tabs = _gel('tl_' + this.moduleId_ + '_header');
        if (tabs) {
            tabs.style.visibility = 'hidden';
        }
    } else {
        a.innerHTML = 'View slideshow &raquo;'
        a.href = 'javascript:void(0);';
        a.onclick = bind(this.viewAlbum, this, title, name);
    }

    var right = _dce('td');
    right.innerHTML =
        '<span class="field">Location: </span>' + location + '<br/>' +
        '<span class="field">Date: </span>' + date.format('mmmm dd, yyyy') + '<br/>' +
        '<span class="field">Number of photos in album: </span>' + numPhotos + '<br/>';
    right.appendChild(a);

    tr.appendChild(left);
    tr.appendChild(right);
    tbody.appendChild(tr);
    table.appendChild(tbody);

    infoWindow.appendChild(p);
    infoWindow.appendChild(table);

    return infoWindow;
};

picasaGadget.prototype.getTabByName = function(tabName) {
    var theTab = null;
    var tabs = this.tabs_.getTabs();
    for (var i=0, tab; tab = tabs[i]; i++) {
        if (html_entity_decode(tab.getName()).indexOf(tabName) == 0) {
            theTab = tab;
            break;
        }
    }
    return theTab;
};

picasaGadget.prototype.viewAlbum = function(albumTitle, albumName) {
    var theTab = this.getTabByName(albumTitle);
    if (theTab) {
        this.tabs_.setSelectedTab(theTab.getIndex());
    } else {
        var title = _dce('span');
        var titleText = document.createTextNode(albumTitle + ' ');

        title.appendChild(titleText);

        this.tabs_.addDynamicTab(title.innerHTML, bind(function(tabId) {
            var tab = _gel(tabId);
            if (tab) {
                var feed  = 'http://picasaweb.google.com/data/feed/api/user/' +
                            this.username_ +
                            '/album/' + albumName +
                            '?imgmax=640&thumbsize=640';
                var options = {
                    displayTime:2000,
                    transistionTime:600,
                    scaleImages:true,
                    fullControlPanel : true,
                    linkTarget : google.feeds.LINK_TARGET_BLANK
            };
                tab.className = 'gadget';
                var ss = new GFslideShow(feed, tabId, options);
            }

        }, this));
        this.tabs_.setSelectedTab(this.tabs_.getTabs().length-1);

        var close = _dce('a');
        close.style.textDecoration = 'none';

        var closeText = document.createTextNode('[x]');
        close.appendChild(closeText);
        close.href = 'javascript:void(0);';
        close.onclick = bind(function(tabIndex) {
            var theTab = this.getTabByName(albumTitle);
            var selectedTabName = this.tabs_.getSelectedTab().getName();
            var removedTab = theTab.getIndex();
            if (this.tabs_.getSelectedTab().getIndex() == removedTab) {
                window.setTimeout(bind(function() { this.tabs_.setSelectedTab(0); }, this), 1);
            } else {
                var tab = this.getTabByName(selectedTabName);
                window.setTimeout(bind(function() { this.tabs_.setSelectedTab(tab.getIndex()); }, this), 1);
            }
            this.tabs_.removeTab(removedTab);
        }, this, albumTitle);

        this.tabs_.getSelectedTab().getNameContainer().appendChild(close);
//        _IG_AdjustIFrameHeight();
    }
};